﻿/*
 * Created by SharpDevelop.
 * User: alex
 * Date: 22.01.2012
 * Time: 19:09
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using System.Drawing;
using System.Collections.Generic;

namespace DrawTest
{
	
	public abstract class FlyingObject
	{
		public FlyingObject()
		{
		}
		
		public bool IsKilled { get; set; }
		
		
		public MyPoint getObjectPosition()
		{
			if (objectPath.Count == 0 && currentPointPosition >= objectPath.Count){
				return null;
			}
			return objectPath[currentPointPosition];
		}
		
		
		protected void loadImage(string imagePath)
		{
			mainImage = Image.FromFile(imagePath);
			
			imageSize.X =mainImage.Width;
			imageSize.Y = mainImage.Height;
		}
		
		protected void initializeFlying(string imagePath, int meanSpeed)
		{
			loadImage(imagePath);
			
			objectPath = new List<MyPoint>();
			
			currentPointPosition=0;
			slowDownCounter = 0;
			this.meanSpeed = meanSpeed;
			IsKilled = false;
			
		}
		
		
		
		protected void drawObject(Graphics dc, int currentAngle)
		{
			MyPoint coordCenterOfRotation = new MyPoint(Consts.CoordCenterOfRotationX,Consts.CoordCenterOfRotationY);
			MyAngleLen angleLen = new MyAngleLen(-1,-1);
			MyPoint objectPosition = getObjectPosition();
			
			if (objectPosition == null){
				IsKilled = true;
				return;
			}
			
			angleLen = FindAngleAndLength(objectPosition,coordCenterOfRotation);
			
			int term = 0;
			if ( currentAngle <= 60 && angleLen.Ang >= 300){
				term = 360;
			}
			
			int delta = angleLen.Ang - currentAngle - term;
			bool greenLight = false;
			
			if (delta <= 0 && delta >= -60 ){
				greenLight = true;
			}
			
			bool greenLightTransparent = false;
			
			if (delta <= -10 && delta >= -60 ){
				greenLightTransparent = true;
			}
			
			int rate = 50-((-delta)-10);
			
			Image modifiedImage;
			if (greenLightTransparent){
				modifiedImage = MakeImageTransparent(mainImage,255-rate*4);
			}
			else{
				modifiedImage = mainImage;
			}
			if (greenLight){
				RectangleF rect = new RectangleF(objectPosition.X - (imageSize.X/2), objectPosition.Y - (imageSize.Y/2), imageSize.X, imageSize.Y);
				dc.DrawImage(modifiedImage, rect);
				
			}
		}
		
		protected bool nextMove()//true if we change iterator
		{
			if (currentPointPosition < objectPath.Count - 1){
				if (slowDownCounter>=meanSpeed){
					currentPointPosition++;
					slowDownCounter=0;
					return true;
				}else{
					slowDownCounter++;
					return false;
				}
			}
			else{
				IsKilled = true;
				return false;
			}
		}
		
		
		
		protected MyPoint imageSize = new MyPoint(-1,-1);
		protected Image mainImage;
		
		
		protected List<MyPoint> objectPath;
		
		
		protected int currentPointPosition;
		protected int meanSpeed;
		protected int slowDownCounter;
		
		////////////////////////////////////////////////////////////////////////////
		/////////////////////////////Help Methods///////////////////////////////////
		///////////////////////////////////////////////////////////////////////////
		
		
		
		
		protected Image MakeImageTransparent(Image image, int transparency)
		{
			Bitmap bitmap = new Bitmap(image);
			for (int i=0; i< bitmap.Width; i++){
				for (int m=0; m< bitmap.Height; m++){
					Color normalColor = bitmap.GetPixel(i,m);
					
					int realTransparency = normalColor.A - transparency;
					if (realTransparency < 0){
						realTransparency = 0;
					}
					if (realTransparency > 255){
						realTransparency = 255;
					}
					Color tempColor = Color.FromArgb(realTransparency, normalColor.R, normalColor.G, normalColor.B);
					bitmap.SetPixel(i,m,tempColor);
				}
			}
			return (Image) bitmap;
		}
		
		
		public static List<MyPoint> findPath(MyPoint start, MyPoint end)
		{
			List<MyPoint> points = new List<MyPoint>();
			points.Add(start);
			MyPoint previouPoint = start;
			
			int am = Math.Abs(start.Y-end.Y);
			int mb = Math.Abs(start.X-end.X);
			
			double max = Math.Max(am,mb);
			for (double i = 1; i < max; i++){
				double lamda =i/(max-i);
				
				double x = (start.X + lamda * end.X) / (lamda + 1);
				double y = (start.Y + lamda * end.Y) / (lamda + 1);
				
				int realX = (int)Math.Round(x);
				int realY = (int)Math.Round(y);
				
				MyPoint point = new MyPoint(realX,realY);
				
				
				//непреривность линии
				MyPoint additionalPoint;
				int differenceNumbersX = point.X - previouPoint.X;
				int differenceNumbersY = point.Y - previouPoint.Y;
				
				if (Math.Abs(differenceNumbersX) == 1 && Math.Abs(differenceNumbersX) == 1){
					
					additionalPoint = new MyPoint(previouPoint.X,point.Y);
					points.Add(additionalPoint);
				} 
				
				previouPoint = point;
				points.Add(point);
			}
			return points;
		}
		
		
		public static  MyAngleLen FindAngleAndLength(MyPoint start, MyPoint end)
		{
			MyAngleLen result = new MyAngleLen(0,0);
			if (start == end){
				return result;//return 0,0
			}
			
			
			int mb = Math.Abs(start.Y-end.Y);
			int am = Math.Abs(start.X-end.X);
			
			double ab = Math.Sqrt(am*am + mb*mb);
			if (start.Y != end.Y && start.X != end.X){
				double cosAlpha = (am*am - ab*ab - mb*mb)/(-ab*mb*2);
				double alpha = Math.Acos(cosAlpha);
				result.Ang = (int)Math.Round(alpha*180/Math.PI);
			}
			result.Len = (int)Math.Round(ab);
			
			if (start.Y < end.Y && start.X >= end.X){
				result.Ang += 0;
			}
			else if(start.Y >= end.Y && start.X > end.X){
				if (result.Ang != 0) {
					result.Ang = 90 - result.Ang;
				}
				if (start.X == 221){
					result.Ang += 89;
				}
				result.Ang += 90;

			}
			else if(start.Y > end.Y && start.X <= end.X){
				result.Ang += 180;
			}
			else if(start.Y <= end.Y && start.X < end.X){
				if (result.Ang != 0) {
					result.Ang = 90 - result.Ang;
				}
				if (start.X == 219 ){
					result.Ang += 89;
				}
				result.Ang += 270;
			}
			else{
				throw new System.ArithmeticException("FindAngleLen: invalid quarter!");
			}
			
			return result;
		}
		
		
		
		/*
		 *                           *
		     ga = gamma        b   *ga *  a
		     al = alpha          *       *
		     be = beta         * al    be  *
		 *  * * * * * *  * 
									c
									
			a/sin(al) = b/sin(be) = c/sin(ga)
			
			We know c (it is length). We know alpha (azimuth)
			gamma = 90;
			beta = 90 - alpha;
			
			We count lenth of b (will be y-coordinate)
			And length of a (will be x-coordinate)
		 */
		public static MyPoint FindDecartPoint(MyPoint start, MyAngleLen angleLen)
		{
			MyPoint result = new MyPoint(-1,-1);
			
			//translate angle to [0, 90)
			
			int signX=1, signY=-1;//0..90 case
			
			if (angleLen.Ang > 90 && angleLen.Ang < 180){
				angleLen.Ang -= 90;
				angleLen.Ang = 90 - angleLen.Ang;
				signX = 1;
				signY = 1;
			}
			else if (angleLen.Ang >= 180 && angleLen.Ang < 270){
				angleLen.Ang -= 180;
				signX = -1;
				signY = 1;
			}
			else if (angleLen.Ang >= 270 && angleLen.Ang < 360){
				angleLen.Ang -= 270;
				angleLen.Ang = 90 - angleLen.Ang;
				signX = -1;
				signY = -1;
			}
			
			if (angleLen.Len !=0){
				
				double alpha = angleLen.Ang*Math.PI/180;
				double gamma = 90*Math.PI/180;
				double beta = gamma - alpha;
				int c = angleLen.Len;
				
				// a/sin(al) = c/sin(ga) =>
				double da = Math.Sin(alpha)*c/Math.Sin(gamma);
				int a = (int)Math.Round(da);
				
				// b/sin(be) = c/sin(ga) =>
				double db =  Math.Sin(beta)*c/Math.Sin(gamma);
				int b = (int)Math.Round(db);
				
				result.Y = start.Y + b*signY;
				result.X = start.X + a*signX;
			}
			else{
				result = start;//no length, then point is the same
			}
			
			return result;
		}
		
	}
}
